<!DOCTYPE html>
<html>
<head><meta name="generator" content="Hexo 3.8.0">
  <meta charset="utf-8">
  

  
  <title>使用 ngrok 实现内网穿透（自建 ngrok 服务器） | ZHB&#39;s Blog</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="有时候我希望能直接通过互联网访问到层层路由下的个人电脑，但是在没有固定 IPv4 的情况下很难做到这一点。一个解决方法就是使用内网穿透技术，而我选择用 ngrok 来实现。ngrok 在 1.x 版本时是开源的，到了 2.x 版本就闭源了。因为自建 ngrok 服务器需要将自己生成的证书编译到客户端中，所以只能使用开源的 1.x 版本从源码编译生成。">
<meta name="keywords" content="Network">
<meta property="og:type" content="article">
<meta property="og:title" content="使用 ngrok 实现内网穿透（自建 ngrok 服务器）">
<meta property="og:url" content="https://gkzhb.github.io/2019/03/ngrok/index.html">
<meta property="og:site_name" content="ZHB&#39;s Blog">
<meta property="og:description" content="有时候我希望能直接通过互联网访问到层层路由下的个人电脑，但是在没有固定 IPv4 的情况下很难做到这一点。一个解决方法就是使用内网穿透技术，而我选择用 ngrok 来实现。ngrok 在 1.x 版本时是开源的，到了 2.x 版本就闭源了。因为自建 ngrok 服务器需要将自己生成的证书编译到客户端中，所以只能使用开源的 1.x 版本从源码编译生成。">
<meta property="og:locale" content="zh-Hans">
<meta property="og:updated_time" content="2019-04-20T14:57:12.113Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="使用 ngrok 实现内网穿透（自建 ngrok 服务器）">
<meta name="twitter:description" content="有时候我希望能直接通过互联网访问到层层路由下的个人电脑，但是在没有固定 IPv4 的情况下很难做到这一点。一个解决方法就是使用内网穿透技术，而我选择用 ngrok 来实现。ngrok 在 1.x 版本时是开源的，到了 2.x 版本就闭源了。因为自建 ngrok 服务器需要将自己生成的证书编译到客户端中，所以只能使用开源的 1.x 版本从源码编译生成。">
  
    <link rel="alternate" href="/atom.xml" title="ZHB&#39;s Blog" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  
    <link rel="stylesheet" href="/css/sourcecodepro.css">
    <!-- <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css"> -->
  
  <link rel="stylesheet" href="/css/style.css">
</head>
</html>
<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">ZHB&#39;s Blog</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="https://gkzhb.github.io"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main"><article id="post-ngrok" class="article article-type-post" itemscope itemprop="blogPost">



  <div class="article-meta">
    <a href="/2019/03/ngrok/" class="article-date">
  <time datetime="2019-03-16T11:18:13.000Z" itemprop="datePublished">2019-03-16</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/Programming/">Programming</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      使用 ngrok 实现内网穿透（自建 ngrok 服务器）
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
		<!-- Table of Contents -->
		
			<div id="toc" class="toc-article">
				<strong class="toc-title">Table of Content</strong>
				<ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#前提条件"><span class="toc-number">1.</span> <span class="toc-text">前提条件</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#生成证书并编译-ngrok-服务端和客户端"><span class="toc-number">2.</span> <span class="toc-text">生成证书并编译 ngrok 服务端和客户端</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#配置并运行服务端与客户端"><span class="toc-number">3.</span> <span class="toc-text">配置并运行服务端与客户端</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#服务端"><span class="toc-number">3.1.</span> <span class="toc-text">服务端</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#客户端"><span class="toc-number">3.2.</span> <span class="toc-text">客户端</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#安装配置和运行"><span class="toc-number">3.2.1.</span> <span class="toc-text">安装、配置和运行</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#使用-systemctl-添加-ngrok-服务"><span class="toc-number">3.2.2.</span> <span class="toc-text">使用 systemctl 添加 ngrok 服务</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#systemctl-使用命令"><span class="toc-number">3.2.2.1.</span> <span class="toc-text">systemctl 使用命令</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#添加自定义-systemctl-服务"><span class="toc-number">3.2.2.2.</span> <span class="toc-text">添加自定义 systemctl 服务</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#参考"><span class="toc-number">4.</span> <span class="toc-text">参考</span></a></li></ol>
			</div>
		
        <p>有时候我希望能直接通过互联网访问到层层路由下的个人电脑，但是在没有固定 IPv4 的情况下很难做到这一点。一个解决方法就是使用内网穿透技术，而我选择用 ngrok 来实现。ngrok 在 1.x 版本时是开源的，到了 2.x 版本就闭源了。因为自建 ngrok 服务器需要将自己生成的证书编译到客户端中，所以只能使用开源的 1.x 版本从源码编译生成。</p>
<a id="more"></a>
<h2 id="前提条件">前提条件</h2>
<ul>
<li>拥有一个域名 免费域名可以在<a href="https://www.freenom.com/" target="_blank" rel="noopener">Freenom</a>上买到，但域名无法在国内备案。</li>
<li>拥有一个有固定 IP 的服务器 购买 VPS 一般都会提供免费固定 IP，而且国内有学生优惠的话，VPS 价格在每月 10 元左右，挺便宜。</li>
</ul>
<h2 id="生成证书并编译-ngrok-服务端和客户端">生成证书并编译 ngrok 服务端和客户端</h2>
<p>ngrok 1.x 版本在 Github 上网址是 [[https://github.com/inconshreveable/ngrok]]，它是用 Go 语言编写的。</p>
<p>编译 ngrok 需要使用相应的编译工具，在 Ubuntu 上可以使用命令来安装这些工具： <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo apt-get install build-essential mercurial git</span><br></pre></td></tr></table></figure></p>
<p>其中，mercurial 和 git 都是版本控制软件。还有最重要的就是安装 golang ，我选择从 golang 官网下载最新版本然后手动安装。安装过程可以参考 Go 的官方文档。</p>
<p>在安装好所需的编译环境后，可以从 Github 上 clone 代码 <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="built_in">clone</span> https://github.com/inconshreveable/ngrok.git</span><br></pre></td></tr></table></figure></p>
<p>在编译之前，要先指定 Go 的工作路径，即编译时源文件所在文件夹的位置：<code>export GOPATH=[Working Directory]</code>，将 <code>[Working Directory]</code> 改为 ngrok 的绝对路径，如果按照上面一步 clone 的话应该是当前工作路径 + <code>/ngrok</code>。在开始编译之前，我们还需要生成我们自己的证书： <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> NGROK_DOMAIN=<span class="string">"[NGROK_BASE_DOMAIN]"</span>  <span class="comment"># 设置环境变量，ngrok 域名</span></span><br><span class="line">openssl genrsa -out rootCA.key 2048</span><br><span class="line">openssl req -x509 -new -nodes -key rootCA.key -subj <span class="string">"/CN=<span class="variable">$NGROK_DOMAIN</span>"</span> -days 5000 -out rootCA.pem</span><br><span class="line">openssl genrsa -out server.key 2048</span><br><span class="line">openssl req -new -key server.key -subj <span class="string">"/CN=<span class="variable">$NGROK_DOMAIN</span>"</span> -out server.csr</span><br><span class="line">openssl x509 -req -<span class="keyword">in</span> server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 5000</span><br></pre></td></tr></table></figure></p>
<p>其中，需要将 <code>[NGROK_BASE_DOMAIN]</code> 替换为你自己将要使用的 ngrok 域名。比如 <code>ngrok.YourDomain.com</code> 或 <code>tunnel.YourDomain.com</code>。我们需要将域名通过 A 记录指向那个拥有固定 IP 的服务器的 IP。在域名 DNS 记录管理中，添加两条 A 记录：主机记录(Host Name)为 <code>*.tunnel</code> 或 <code>*.ngrok</code> 即你将要使用的 ngrok 子域名，另一条主机记录为 <code>tunnel</code> 或 <code>ngrok</code> 就是将前面的 <code>*.</code> 去掉，第二条主机记录应该可以不加。这两条记录类型(Record Type)都为 A 类型，IP 地址指向服务器的固定 IP 。 不过我在 Freenom 上无法添加 <code>*.ngrok</code> 主机记录，估计是 DNS 服务商不支持通配符 <code>*</code>，所以我只能根据自己的需要手动添加多条 <code>[service].ngrok</code> 记录，<code>[service]</code> 更改为需要使用的二级域名。 在执行完上面的 openssl 命令后，会生成六个文件，将其中几个文件移动到 ngrok 仓库的指定位置： <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cp rootCA.pem <span class="variable">$GOPATH</span>/assets/client/tls/ngrokroot.crt  <span class="comment"># 复制rootCA.pem到assets/client/tls/并更名为ngrokroot.crt</span></span><br><span class="line">cp server.crt <span class="variable">$GOPATH</span>/assets/server/tls/snakeoil.crt <span class="comment"># 复制server.crt到assets/server/tls/并更名为snakeoil.crt</span></span><br><span class="line">cp server.key <span class="variable">$GOPATH</span>/assets/server/tls/snakeoil.key <span class="comment"># 复制server.key到assets/server/tls/并更名为snakeoil.key</span></span><br></pre></td></tr></table></figure></p>
<p>之后，我们就可以开始编译 ngrok 了: <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">GOOS=[OS] GOARCH=[CPU ARCH] make release-server <span class="comment"># 编译服务端</span></span><br><span class="line">GOOS=[OS] GOARCH=[CPU ARCH] make release-client <span class="comment"># 编译客户端</span></span><br></pre></td></tr></table></figure></p>
<p>将 <code>[OS]</code> 换成对应的操作系统 <code>linux</code> <code>windows</code> <code>android</code>，<code>[CPU ARCH]</code> 换成对应的 CPU 架构 <code>386</code>(32位 x86) <code>amd64</code>(64位 x86-64)。具体组合见 <a href="https://stackoverflow.com/questions/20728767/all-possible-goos-value/20728862" target="_blank" rel="noopener">StackOverflow</a>： <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">$GOOS $GOARCH</span><br><span class="line">android   arm</span><br><span class="line">darwin    386</span><br><span class="line">darwin    amd64</span><br><span class="line">darwin    arm</span><br><span class="line">darwin    arm64</span><br><span class="line">dragonfly amd64</span><br><span class="line">freebsd   386</span><br><span class="line">freebsd   amd64</span><br><span class="line">freebsd   arm</span><br><span class="line">linux     386</span><br><span class="line">linux     amd64</span><br><span class="line">linux     arm</span><br><span class="line">linux     arm64</span><br><span class="line">linux     ppc64</span><br><span class="line">linux     ppc64le</span><br><span class="line">linux     mips</span><br><span class="line">linux     mipsle</span><br><span class="line">linux     mips64</span><br><span class="line">linux     mips64le</span><br><span class="line">netbsd    386</span><br><span class="line">netbsd    amd64</span><br><span class="line">netbsd    arm</span><br><span class="line">openbsd   386</span><br><span class="line">openbsd   amd64</span><br><span class="line">openbsd   arm</span><br><span class="line">plan9     386</span><br><span class="line">plan9     amd64</span><br><span class="line">solaris   amd64</span><br><span class="line">windows   386</span><br><span class="line">windows   amd64</span><br></pre></td></tr></table></figure></p>
<p>常用 <code>windows</code> + <code>amd64</code> 或者 <code>linux</code> + <code>amd64</code> 组合。<br>
编译完成后在 <code>$GOPATH/bin</code> 下可以看到 <code>ngrok</code> <code>ngrokd</code> 两个文件，如果编译 windows 平台的会有 <code>.exe</code> 后缀。服务端文件是 <code>ngrokd</code>，客户端文件为 <code>ngrok</code>。</p>
<h2 id="配置并运行服务端与客户端">配置并运行服务端与客户端</h2>
<h3 id="服务端">服务端</h3>
<p>服务器上可以将 <code>ngrokd</code> 与之前生成的证书 <code>server.crt</code> <code>server.key</code> 放在同一个目录中，并在目录中创建一个脚本文件 <code>run.sh</code> 来启动 ngrokd： <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line">./ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain=<span class="string">"[NGROK_BASE_DOMAIN]"</span> -httpAddr=<span class="string">":[PORT]"</span> -httpsAddr=<span class="string">":[PORT]"</span></span><br></pre></td></tr></table></figure></p>
<p>将中括号部份换成实际需要的值。后两个 <code>[PORT]</code> 指定 ngrok 在服务器上 http 和 https 协议使用的端口。<br>
服务端运行起来之后，可以通过浏览器访问之前设置 DNS 记录的子域名，注意如果端口不是默认的，需要在域名后添加 <code>:[PORT]</code>。如果网页显示类似 <code>Tunnel ngrok.YourDomain.com:[PORT] not found</code> 字样则说明服务器成功启动。</p>
<h3 id="客户端">客户端</h3>
<h4 id="安装配置和运行">安装、配置和运行</h4>
<p>客户端方面，注意要使用之前编译生成的 ngrok，似乎也可以使用 <a href="https://github.com/hauntek/python-ngrok" target="_blank" rel="noopener">python-ngork</a> 但我没有成功。客户端方面，需要新建配置文件 <code>ngrok.cfg</code>（使用 yaml 语法格式），内容如下： <figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server_addr:</span> <span class="string">[NGROK_BASE_DOMAIN]:4443</span></span><br><span class="line"><span class="attr">trust_host_root_certs:</span> <span class="literal">false</span></span><br></pre></td></tr></table></figure></p>
<p>这里 4443 是 ngrokd 默认的监听端口。<br>
之后通过命令运行（同样可以将这条命令写成脚本）：<code>./ngrok -subdomain [SUBDOMAIN] -config=[YOUR_CONFIG_FILE_NAME] [PORT]</code> 这是将客户端本地 80 端口代理到服务器对应的 httpAddr 端口。<br>
同样可以代理 TCP 的端口：<code>./ngrok -subdomain mydatabaseserver -config=[YOUR_CONFIG_FILE_NAME] -proto tcp 3306</code> 将 mysql 的 3306 端口代理到服务器上，这样就可以通过域名 + 端口访问到客户端对应的端口上的服务。</p>
<p>不过这样设置并不方便，写入配置文件 <code>ngrok.cfg</code> 然后选择需要的代理更加便捷： <figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server_addr:</span> <span class="string">ngrok.YourDomain.com:4443</span></span><br><span class="line"><span class="attr">trust_host_root_certs:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">tunnels:</span></span><br><span class="line"><span class="attr">  http:</span></span><br><span class="line"><span class="attr">    subdomain:</span> <span class="string">"http"</span></span><br><span class="line"><span class="attr">    proto:</span></span><br><span class="line"><span class="attr">      http:</span> <span class="string">"4000"</span></span><br><span class="line"><span class="attr">  ssh:</span></span><br><span class="line"><span class="attr">    subdomain:</span> <span class="string">"zhb"</span></span><br><span class="line"><span class="attr">    remote_port:</span> <span class="number">4422</span></span><br><span class="line"><span class="attr">    proto:</span></span><br><span class="line"><span class="attr">      tcp:</span> <span class="string">"22"</span></span><br></pre></td></tr></table></figure></p>
<p><code>remote_port</code> 表示指定 TCP 在服务器上监听的端口。注意不要使用 Tab 而应该用空格进行缩进。 最后通过命令 <code>./ngrok -config=ngrok.cfg start ssh</code> 启动 tunnels 中的 ssh 代理。start 后可以接多个代理名称，中间用空格分格。<br>
更多客户端配置文件选项可以访问 ngork 官网的文档进行了解（2.x 的配置文件应该是兼容的吧）。</p>
<h4 id="使用-systemctl-添加-ngrok-服务">使用 systemctl 添加 ngrok 服务</h4>
<h5 id="systemctl-使用命令">systemctl 使用命令</h5>
<p>以下的 <code>[Service Name].service</code> 中的 <code>.service</code> 可以省略，即使用 <code>[Service Name]</code> 即可。 <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">$ systemctl start [Service Name].service <span class="comment"># 启动 [Service Name] 服务</span></span><br><span class="line">$ systemctl stop [Service Name].service <span class="comment"># 停止 [Service Name] 服务</span></span><br><span class="line">$ systemctl restart [Service Name].service <span class="comment"># 重启 [Service Name] 服务</span></span><br><span class="line">$ systemctl status [Service Name].service <span class="comment"># 查看 [Service Name] 服务运行状态</span></span><br><span class="line">$ systemctl <span class="built_in">enable</span> [Service Name].service <span class="comment"># 设置 [Service Name] 服务开机自启动</span></span><br><span class="line">$ systemctl <span class="built_in">disable</span> [Service Name].service <span class="comment"># 关闭 [Service Name] 服务开机自启动</span></span><br><span class="line">$ systemctl daemon-reload <span class="comment"># 重新载入 systemd,扫描新的或有变动的单元</span></span><br></pre></td></tr></table></figure></p>
<p>下面我们将新建一个自定义的 ngrok 服务。</p>
<h5 id="添加自定义-systemctl-服务">添加自定义 systemctl 服务</h5>
<p>新建配置文件 <code>ngrok.service</code>，内容如下： <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line">Description=Share local port(s) with ngrok</span><br><span class="line">After=syslog.target network.target</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">PrivateTmp=true</span><br><span class="line">Type=simple</span><br><span class="line">Restart=always</span><br><span class="line">RestartSec=1min</span><br><span class="line">StandardOutput=null</span><br><span class="line">StandardError=null</span><br><span class="line">ExecStart=/usr/local/ngrok/ngrok -config=/usr/local/ngrok/ngrok.cfg start ssh</span><br><span class="line">#ExecStop=/usr/bin/killall ngrok</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</span><br></pre></td></tr></table></figure></p>
<p>注意要修改你的 <code>ExecStart</code> 项的值，这项的值与上面的运行命令类似，不过注意 ngrok 客户端和配置文件要使用绝对路径。<code>ExecStop</code> 这项我将它注释掉了，这个命令可能误杀进程，所以不建议使用它。systemctl 有默认的 <code>ExecStop</code> 命令，具体可以参考 <a href="https://stackoverflow.com/questions/40411338/how-stop-systemd-service" target="_blank" rel="noopener">linux - how stop systemd service - Stack Overflow</a> 中 Umut 的回答。<br>
将文件 <code>ngrok.service</code> 复制到路径 <code>/usr/lib/systemd/system/</code> 下（需要 root 权限）。然后执行命令使其开机启动与生效： <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ systemctl <span class="built_in">enable</span> ngrok.service</span><br><span class="line">$ systemctl daemon-reload</span><br></pre></td></tr></table></figure></p>
<p>最后，可以通过命令 <code>systemctl start ngrok.service</code> 启动 ngrok 服务，使用命令 <code>systemctl stop ngrok.service</code> 停止 ngrok 服务，使用 <code>systemctl status ngrok.service</code> 查看 ngrok 服务的运行状态。</p>
<h2 id="参考">参考</h2>
<ul>
<li><a href="https://www.svenbit.com/2014/09/run-ngrok-on-your-own-server/" target="_blank" rel="noopener">Run Ngrok on Your Own Server - svenbit</a></li>
<li><a href="https://blog.csdn.net/zhangguo5/article/details/77848658" target="_blank" rel="noopener">一分钟实现内网穿透（ngrok服务器搭建） - 学习笔记 - CSDN博客</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/29019562" target="_blank" rel="noopener">Ngrok完美实现内网穿透 - 知乎</a></li>
<li><a href="https://cangshui.net/?p=1943" target="_blank" rel="noopener">安卓端搭建网站+自建内网穿透ngrok – 沧水的博客</a></li>
<li>systemctl 配置
<ul>
<li><a href="https://blog.csdn.net/qazx123q/article/details/81212858" target="_blank" rel="noopener">Centos 7 ngrok 加入系统服务，支持开启和关闭服务 - opfan的博客 - CSDN博客</a></li>
<li><a href="https://www.jianshu.com/p/79059b06a121" target="_blank" rel="noopener">CentOS7使用systemctl添加自定义服务 - 简书</a> <strong>详细</strong></li>
<li><a href="https://stackoverflow.com/questions/40411338/how-stop-systemd-service" target="_blank" rel="noopener">linux - how stop systemd service - Stack Overflow</a></li>
<li><a href="https://www.cnblogs.com/saneri/p/7778756.html" target="_blank" rel="noopener">CentOS7利用systemctl添加自定义系统服务 - 梦徒 - 博客园</a></li>
<li><a href="https://www.freedesktop.org/software/systemd/man/systemd.service.html" target="_blank" rel="noopener">systemd.service 文档</a></li>
</ul></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="https://gkzhb.github.io/2019/03/ngrok/" data-id="cjx8qksqc0012nrw8lddw4qmt" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Network/">Network</a></li></ul>

    </footer>
  </div>
  
    
<nav id="article-nav">
  
    <a href="/2019/04/wallabag/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Newer</strong>
      <div class="article-nav-title">
        
          自建”稍后阅读“服务—— wallabag
        
      </div>
    </a>
  
  
    <a href="/2019/02/hexo-tag-plugins/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">Hexo 标签插件使用</div>
    </a>
  
</nav>

  
</article>


</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Landscape/">Landscape</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Linux/">Linux</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Programming/">Programming</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Self-hosting/">Self-hosting</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Software/">Software</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/Anki/">Anki</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Blog/">Blog</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Command-Line/">Command Line</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Data-Structure/">Data Structure</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Games/">Games</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Hometown/">Hometown</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Linux/">Linux</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Network/">Network</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Read-It-Later/">Read-It-Later</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Recall/">Recall</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Regular-Expression/">Regular Expression</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Server/">Server</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Spring/">Spring</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/折腾/">折腾</a></li></ul>
    </div>
  </div>


  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2019 Haibin Zhang<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    

<!-- <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script> -->

<!-- <script src="http://apps.bdimg.com/libs/jquery/2.0.3/jquery.min.js"></script> -->
<script src="/mathjax/MathJax.js?config=TeX-MML-AM_CHTML"></script>
<script src="/js/jquery.min.js"></script>

  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css">
  <script src="/fancybox/jquery.fancybox.pack.js"></script>


<script src="/js/script.js"></script>




  </div>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
		messageStyle: "none",
		showProcessingMessages: false,
        tex2jax: {
            inlineMath: [ ["$","$"], ["\\(","\\)"] ],
            skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'],
            processEscapes: true
        }
    });
    MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax();
        for (var i = 0; i < all.length; ++i)
            all[i].SourceElement().parentNode.className += ' has-jax';
    });
</script>
<!-- <script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script> -->
<script src="/mathjax/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>

</body>
</html>